/*
 * AIEngine a new generation network intrusion detection system.
 *
 * Copyright (C) 2013-2023  Luis Campo Giralte
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 * Written by Luis Campo Giralte <luis.camp0.2009@gmail.com>
 *
 */
#include "test_quic.h"

#define BOOST_TEST_DYN_LINK
#ifdef STAND_ALONE_TEST
#define BOOST_TEST_MODULE quictest
#endif
#include <boost/test/unit_test.hpp>

using namespace aiengine;

BOOST_FIXTURE_TEST_SUITE(quic_test_suite, StackQuictest)

BOOST_AUTO_TEST_CASE (test01)
{
	Packet packet;

        BOOST_CHECK(quic->getTotalPackets() == 0);
        BOOST_CHECK(quic->getTotalValidPackets() == 0);
        BOOST_CHECK(quic->getTotalBytes() == 0);
        BOOST_CHECK(quic->getTotalInvalidPackets() == 0);
	BOOST_CHECK(quic->processPacket(packet) == true);

	CounterMap c = quic->getCounters();
}

BOOST_AUTO_TEST_CASE (test02)
{
        Packet packet("../quic/packets/packet01.pcap");

	BOOST_CHECK(quic->isDynamicAllocatedMemory() == false);

	inject(packet);

        BOOST_CHECK(ip->getTotalPackets() == 1);
        BOOST_CHECK(ip->getTotalValidPackets() == 1);
        BOOST_CHECK(ip->getTotalBytes() == 1378);
        BOOST_CHECK(ip->getTotalInvalidPackets() == 0);

        BOOST_CHECK(quic->getTotalPackets() == 1);
        BOOST_CHECK(quic->getTotalValidPackets() == 1);
        BOOST_CHECK(quic->getTotalBytes() == 1350);
        BOOST_CHECK(quic->getTotalInvalidPackets() == 0);

	Json j;

	quic->statistics(j, 5);
}

BOOST_AUTO_TEST_CASE (test03)
{
        Packet packet("../quic/packets/packet02.pcap");

	quic->increaseAllocatedMemory(1);

	inject(packet);

        BOOST_CHECK(ip->getTotalPackets() == 1);
        BOOST_CHECK(ip->getTotalValidPackets() == 1);
        BOOST_CHECK(ip->getTotalBytes() == 1378);
        BOOST_CHECK(ip->getTotalInvalidPackets() == 0);

        BOOST_CHECK(quic->getTotalPackets() == 1);
        BOOST_CHECK(quic->getTotalValidPackets() == 1);
        BOOST_CHECK(quic->getTotalBytes() == 1350);
        BOOST_CHECK(quic->getTotalInvalidPackets() == 0);

	Flow *flow = quic->getCurrentFlow();

	BOOST_CHECK(flow != nullptr);

	auto info = flow->getQuicInfo();
	BOOST_CHECK(info != nullptr);

	Json j;

	quic->statistics(j, 5);

	quic->releaseCache();
}

// Verify the extraction of the server name
BOOST_AUTO_TEST_CASE (test04)
{
        Packet packet("../quic/packets/packet02.pcap");

        quic->increaseAllocatedMemory(1);

        inject(packet);

        BOOST_CHECK(ip->getTotalPackets() == 1);
        BOOST_CHECK(ip->getTotalValidPackets() == 1);
        BOOST_CHECK(ip->getTotalBytes() == 1378);
        BOOST_CHECK(ip->getTotalInvalidPackets() == 0);

        BOOST_CHECK(quic->getTotalPackets() == 1);
        BOOST_CHECK(quic->getTotalValidPackets() == 1);
        BOOST_CHECK(quic->getTotalBytes() == 1350);
        BOOST_CHECK(quic->getTotalInvalidPackets() == 0);

        Flow *flow = quic->getCurrentFlow();

        BOOST_CHECK(flow != nullptr);

        auto info = flow->getQuicInfo();
        BOOST_CHECK(info != nullptr);

	std::string host("mail.google.com");

	BOOST_CHECK(info->server_name != nullptr);
	BOOST_CHECK(host.compare(info->server_name->name()) == 0);

        Json j;

	flow->show(j);

	BOOST_CHECK(host.compare(j["quic"]["host"]) == 0);
	BOOST_CHECK(j["proto"] == IPPROTO_UDP);
}

// Verify the extraction of the server name
BOOST_AUTO_TEST_CASE (test05)
{
        Packet packet("../quic/packets/packet03.pcap");

        quic->increaseAllocatedMemory(1);

        inject(packet);

        BOOST_CHECK(ip->getTotalPackets() == 1);
        BOOST_CHECK(ip->getTotalValidPackets() == 1);
        BOOST_CHECK(ip->getTotalBytes() == 1378);
        BOOST_CHECK(ip->getTotalInvalidPackets() == 0);

        BOOST_CHECK(quic->getTotalPackets() == 1);
        BOOST_CHECK(quic->getTotalValidPackets() == 1);
        BOOST_CHECK(quic->getTotalBytes() == 1350);
        BOOST_CHECK(quic->getTotalInvalidPackets() == 0);

        Flow *flow = quic->getCurrentFlow();

        BOOST_CHECK(flow != nullptr);

        auto info = flow->getQuicInfo();
        BOOST_CHECK(info != nullptr);

	std::string host("docs.google.com");

	BOOST_CHECK(info->server_name != nullptr);
	BOOST_CHECK(host.compare(info->server_name->name()) == 0);

        Json j;

	flow->show(j);

	BOOST_CHECK(host.compare(j["quic"]["host"]) == 0);
	BOOST_CHECK(j["proto"] == IPPROTO_UDP);

	Json jc;

	quic->statistics(jc, "hosts", std::numeric_limits<int>::max());
}

BOOST_AUTO_TEST_CASE (test06)
{
        Packet packet("../quic/packets/packet04.pcap");
        auto dom = SharedPointer<DomainName>(new DomainName("Gafas", ".google.com"));
        auto dm = SharedPointer<DomainNameManager>(new DomainNameManager());

        dm->addDomainName(dom);

        quic->setDomainNameManager(dm);

        quic->increaseAllocatedMemory(1);

        inject(packet);

        BOOST_CHECK(ip->getTotalPackets() == 1);
        BOOST_CHECK(ip->getTotalValidPackets() == 1);
        BOOST_CHECK(ip->getTotalBytes() == 1378);
        BOOST_CHECK(ip->getTotalInvalidPackets() == 0);

        BOOST_CHECK(quic->getTotalPackets() == 1);
        BOOST_CHECK(quic->getTotalValidPackets() == 1);
        BOOST_CHECK(quic->getTotalBytes() == 1350);
        BOOST_CHECK(quic->getTotalInvalidPackets() == 0);
        BOOST_CHECK(quic->getTotalEvents() == 1); // The match

        Flow *flow = quic->getCurrentFlow();

        BOOST_CHECK(flow != nullptr);

        auto info = flow->getQuicInfo();
        BOOST_CHECK(info != nullptr);

        std::string host("clients4.google.com");

        BOOST_CHECK(info->server_name != nullptr);
        BOOST_CHECK(host.compare(info->server_name->name()) == 0);

	BOOST_CHECK(info->matched_domain_name != nullptr);
	BOOST_CHECK(info->matched_domain_name == dom);

        Json j;

        flow->show(j);

        BOOST_CHECK(host.compare(j["quic"]["host"]) == 0);
        BOOST_CHECK(j["proto"] == IPPROTO_UDP);

        // some outputs
        std::filebuf fb;
        fb.open ("/dev/null",std::ios::out);
        std::ostream outp(&fb);
        outp << *info.get();
        flow->show(outp);
        fb.close();

	quic->decreaseAllocatedMemory(1);

	quic->releaseFlowInfo(flow);

	quic->setDomainNameManager(dm);
	quic->setDomainNameManager(nullptr);
}

// Two different flow sharing the host and user agents
BOOST_AUTO_TEST_CASE (test07)
{
        Packet packet("../quic/packets/packet04.pcap", 14 + 20 + 8);

        auto flow1 = SharedPointer<Flow>(new Flow());
        auto flow2 = SharedPointer<Flow>(new Flow());

        flow1->setFlowDirection(FlowDirection::FORWARD);
        flow1->packet = const_cast<Packet*>(&packet);
        flow2->setFlowDirection(FlowDirection::FORWARD);
        flow2->packet = const_cast<Packet*>(&packet);

	quic->increaseAllocatedMemory(2);
	quic->setDynamicAllocatedMemory(true);
	BOOST_CHECK(quic->isDynamicAllocatedMemory() == true);

	flow1->total_packets[0] = 1;
	flow2->total_packets[0] = 1;

        quic->processFlow(flow1.get());
        quic->processFlow(flow2.get());

        SharedPointer<QuicInfo> info1 = flow1->getQuicInfo();
        SharedPointer<QuicInfo> info2 = flow2->getQuicInfo();
        BOOST_CHECK(info1 != nullptr);
        BOOST_CHECK(info2 != nullptr);
        BOOST_CHECK(info1 != info2);
        BOOST_CHECK(info1->server_name != nullptr);
        BOOST_CHECK(info2->server_name != nullptr);
        BOOST_CHECK(info1->server_name == info2->server_name);
        BOOST_CHECK(info1->user_agent == info2->user_agent);

        Json jc;

	quic->statistics(jc, "hosts", 1);
	quic->statistics(jc, "useragents", 1);

	BOOST_CHECK(jc["Chrome/52.0.2743.116 Linux x86_64"] == 2);
	BOOST_CHECK(jc["clients4.google.com"] == 2);
}

BOOST_AUTO_TEST_CASE (test08)
{
        Packet packet("../quic/packets/packet04.pcap", 14 + 20 + 8);
	std::vector<SharedPointer<Flow>> flows;

	quic->setDynamicAllocatedMemory(true);

	for (int i = 0; i < 20; ++i) {
		auto flow = SharedPointer<Flow>(new Flow());

		flow->setId(i);
		flow->total_packets[0] = 1;
		flow->setFlowDirection(FlowDirection::FORWARD);
		flow->packet = const_cast<Packet*>(&packet);

		flow_mng->add(flow);
		flows.push_back(flow);
		quic->processFlow(flow.get());
	}

	BOOST_CHECK(flow_mng->getTotalFlows() == 20);
        BOOST_CHECK(quic->isDynamicAllocatedMemory() == true);

	quic->releaseCache();
}

BOOST_AUTO_TEST_SUITE_END()

